/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.client;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.JIntellitype;
import listo.utils.FileUtils2;
import listo.utils.logging.Log;

import javax.swing.*;
import java.awt.event.InputEvent;
import java.io.File;

@Singleton
public class GlobalHotKeySupport {

    public static final int HOTKEY_OPEN_WINDOW = 0x01;
    public static final int HOTKEY_NEW_TASK = 0x02;

    private JIntellitype intellitype;

    @Inject
    public GlobalHotKeySupport(final Log log, Preferences preferences, Application application) {
        try {
            String os = System.getProperty("os.name").toLowerCase();
            String architecture = System.getProperty("sun.arch.data.model").toLowerCase();
            if (!os.startsWith("windows") || !"32".equalsIgnoreCase(architecture)) {
                log.info("System is not Win32, no global hotkey support available");
                return;
            }
        }
        catch (SecurityException e) {
            throw new IllegalStateException(e);
        }

        // load hotkey DLL
        try {
            // extract the hotkey DLL from the resources
            String tempFile = FileUtils2.getTempFileName("JIntellitype.dll");
            log.debug("Loading global hotkey dll %1$s", tempFile);
            if (!new File(tempFile).exists()) {
                log.debug("Doesn't exist, copying from resource");
                byte[] dll = FileUtils2.readAllBytesFromResource("lib/JIntellitype.dll");
                FileUtils2.writeAllBytes(dll, tempFile);
            }
            System.load(tempFile);
        }
        catch (Exception e) {
            log.error(e.getMessage());
            log.error("Could not load hotkey dll, global hotkey support disabled");
            return;
        }

        long owStroke = getIntellitypeHotKey(preferences.getOpenWindowHotKey());
        if (owStroke == 0) throw new RuntimeException("Error in preference file: Illegal openWindowHotKey");

        long ntStroke = getIntellitypeHotKey(preferences.getNewTaskHotKey());
        if (ntStroke == 0) throw new RuntimeException("Error in preference file: Illegal newTaskHotKey");

        intellitype = JIntellitype.getInstance();

        application.addShutdownListener(new Application.ShutdownListener() {
            public void onShutdown() {
                log.debug("Uninstalling global hotkey support");
                intellitype.cleanUp();
            }
        });

        intellitype.registerHotKey(HOTKEY_OPEN_WINDOW, (int) (owStroke >>> 32), (int) owStroke);
        intellitype.registerHotKey(HOTKEY_NEW_TASK, (int) (ntStroke >>> 32), (int) ntStroke);
        log.debug("Global hotkeys registered");
    }

    private static long getIntellitypeHotKey(KeyStroke swingKeyStroke) {
        if (swingKeyStroke == null) return 0;

        int smod = swingKeyStroke.getModifiers();
        int imod = 0;
        if ((smod & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK) imod += JIntellitype.MOD_SHIFT;
        if ((smod & InputEvent.ALT_MASK) == InputEvent.ALT_MASK) imod += JIntellitype.MOD_ALT;
        if ((smod & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) imod += JIntellitype.MOD_CONTROL;
        if ((smod & InputEvent.META_MASK) == InputEvent.META_MASK) imod += JIntellitype.MOD_WIN;
        return (((long) imod) << 32) + swingKeyStroke.getKeyCode();
    }

    public boolean isAvailable() {
        return intellitype != null;
    }

    public void addHotKeyListener(HotkeyListener listener) {
        if (intellitype != null) {
            intellitype.addHotKeyListener(listener);
        }
    }
}
